#include "Logger.h"
#include "Channel.h"
#include "EpollPoller.h"

#include <errno.h>

// index_ 表示这三个状态
// channel未添加到poller中
const int kNew = -1;
// channel已添加到poller中
const int kAdded = 1;
// channel从poller中移除
const int kDeleted = 2;

EpollPoller::EpollPoller(EventLoop* loop)
    : Poller(loop), epollfd_(::epoll_create1(EPOLL_CLOEXEC)), events_(kInitEventListSize)
{
    if(epollfd_<0)
    {
        LOG_FATAL("epoll_creat error:%d \n",errno);
    }

}

EpollPoller::~EpollPoller()
{
    ::close(epollfd_);
}

// 等待事件发生 并将活跃事件对应的Channel收集起来
Timestamp EpollPoller::poll(int timeoutMs,ChannelList* activeChannels) 
{
    LOG_INFO("func=%s fd total count:%lu \n",__FUNCTION__,channels_.size());

    int numEvents=::epoll_wait(epollfd_,&*events_.begin(),static_cast<int>(events_.size()),timeoutMs);
    int saveErrno=errno;
    Timestamp now(Timestamp::now());

    if(numEvents>0)
    {
        LOG_INFO("%d events happened \n",numEvents);
        fillActiveChannels(numEvents,activeChannels);
        if(numEvents == events_.size())
        {
            events_.resize(events_.size()*2);
        }
    }
    else if(numEvents == 0)
    {
        LOG_DEBUG("%s timeout! \n"__FUNCTION__);
    }
    else
    {
        if(saveErrno!=EINTR)
        {
            errno=saveErrno;
            LOG_ERROR("EpollPoller::poll() err!");
        }
    }
    return now;

}

// 从poller中删除channel
void EpollPoller::removeChannel(Channel* channel)
{
    int fd=channel->fd();
    int index=channel->index();

    LOG_INFO("func=%s fd=%d \n",__FUNCTION__,fd);

    channels_.erase(fd);
    if(index == kAdded)
    {
        update(EPOLL_CTL_DEL,channel);
    }
    channel->set_index(kNew);

}

void EpollPoller::updateChannel(Channel* channel) 
{
    const int index=channel->index();
    LOG_INFO("func=%s fd=%d events=%d index=%d \n",__FUNCTION__,channel->fd(),channel->events(),index);

    if(index == kNew || index == kDeleted)
    {
        // 未注册过
        if(index == kNew)
        {
            int fd = channel->fd();
            channels_[fd]=channel;
        }
        // 统一将状态设为kAdded 并调用update(EPOLL_CTL_ADD, channel)向epoll注册事件

        // 重新使用
        channel->set_index(kAdded);
        update(EPOLL_CTL_ADD,channel);
    }
    else // channel已经在poller上注册过了
    {
        int fd=channel->fd();
        if(channel->isNoneEvent())
        {
            update(EPOLL_CTL_DEL,channel);
            channel->set_index(kDeleted);
        }
        else
        {
            update(EPOLL_CTL_MOD,channel);
        }

    }
}


// 填写活跃链接
void EpollPoller::fillActiveChannels(int numEvents,ChannelList* activeChannels) const
{
    for(int i=0;i<numEvents;i++)
    {   // events_  ->  vector<epoll_event>
        // 注册事件时 代码已经提前将 Channel* (update处) 赋值给了 data.ptr 此处强转为还原过去
        Channel* channel =static_cast<Channel*> (events_[i].data.ptr); 
        // 设置文件描述符实际发生的事 
        channel->set_revents(events_[i].events);
        // EventLoop就拿到了它的poller给它返回的所有发生事件的channle列表
        activeChannels->push_back(channel); 
    }
}
// 更新channel通道事件
void EpollPoller::update(int operation,Channel* channel)
{
    epoll_event event;
    memset(&event,0,sizeof(event));

    int fd=channel->fd();

    event.events=channel->events();
    event.data.fd=fd;
    event.data.ptr=channel;
    

    if(::epoll_ctl(epollfd_,operation,fd,&event)<0)
    {
        if(operation == EPOLL_CTL_DEL)
        {
            LOG_ERROR("epoll_ctl del error:%d \n",errno);
        } 
        else
        {
            LOG_FATAL("epoll_ctl add/mod error:%d \n",errno);
        }
    }
}
